<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <title>Safe AJAX: Beware the Asynchronous</title>
</head>
<body>
    <h1>Safe AJAX: Beware the Asynchronous</h1>
    William Connor, cipherbill@blueholesoftware.com, Sept. 1<sup>st</sup>, 2007
    <h2>Abstract</h2>
    <p>
        Most AJAX applications, even some from big names like Apple and Google, are broken. Used to the single threaded
        simplicity of JavaScript, we have forgotten (or never knew, perhaps) the tricky dual proposition of asynchronous,
        remote communications. We have forgotten how to guard against responses that arrive out of order or not at all.
        We have forgotten what idempotent means and why it is desirable for remote operations. The problem domain
        resembles, and is no less difficult, than multi-threaded or multi-transaction programming and
        we must be 'on' to play the AJAX game. As Java gave us 'synchronized' (yes, I know monitors and such predate Java
        by decades, but allow me popular license) to deal with threads, AJAX frameworks owe us mechanisms for taming
        asynchronous requests. There are many ways to go; in this paper I show the path we took with the Blue Hole
        Framework (BHF) and encourage other AJAX framework owners to provide the mechanism they find best, but at least
        recognize the problem and provide <em>something</em>
    </p>
    <h2>The Problems</h2>
    <p>
        AJAX confounds us with <em>remote operation</em>s and <em>asynchronous responses</em>. Remote operations are fundamentally
        unreliable and introduce two modes of failure: an error within the remote method or an error in the invocation
        mechanism. (This is why Java Remote Method Invocation (RMI) introduced <code>RemoteException</code>). If you
        receive a response from the server, you know if the operation succeeded or failed. If something went wrong
        with the dispatch <em>mechanism</em>, you did not know if the operation succeeded or failed. The operation
        may have succeeded, but the network fried just as you were receiving the result. This is why we must
        distinguish between an error in the remote method (we know it failed) from an error in the mechanism
        (we don't know one way or the other.) If we want a semblance of reliability in our application, we will retry
        in the later case, but not in the former (without some intervening action that might correct the problem.) If
        we retry, we run the risk of repeating the operation, if it succeeded: remember we don't know. It would
        be convenient, to say the least, if the operation was idempotent. Thus, our first step as competent AJAX
        programmers is to structure our remote operations to be idempotent.
    </p><p>
        <em>Asynchronous responses</em> means that state can change while an operation is pending and that the results of pending
        operations may arrive out of order (if it all.) Each time you receive a response back from the server, you
        need to figure out whether or not the response is still (after all that's happened since the operation
        was dispatched: user interaction, other responses received in the meantime, ...) appropriate. If not, what
        do you do? Fail? Ignore? Retry with the current state? Maybe someday we'll have a pat answer, but for the moment
        it seems that a retry with current state is the safe response to most, but not all, situations.
    </p><p>
        We could avoid all this fuss by using synchronous requests, no? Unfortunately, not quite. Even if you use
        <code>XmlHTTPRequest</code> in synchronous mode, the user can queue events such as mouse clicks while the
        operation is pending. Does the response still make sense given what the user has done in the mean time?
        Should the user's actions be thrown away given the response? Tough questions with application specific
        answers. The best advice I have is to at least ask the questions and do your best to codify the answers.
        Even in high profile discussion areas, such as ajaxian.com, you see pundits suggest that allowing only one
        request at a time should take care of it. Now you know that the answer could not possibly be that simple.
    </p>
    <h2>An Example</h2>
    <p>
        For our first example, consider a calculator where we keep state (the accumulated value) client side and
        perform the operations (add,sub,mul,div,clear) server side. The user enters an operand and clicks on an
        operator. In response, our calculator sends the accumulated value, operand, and operator to the server
        for the expensive computation. When the result is returned, the calculator replace the accumulated value
        with the returned result. That's the setup.
    </p><p>
        Let's say the round trip time is around 250ms: not unusual. Our user enters 5 as the operand and quickly
        clicks the 'add' button twice. Yikes! The accumulated value is 5 rather than the expected 10! What went
        wrong? The first click sent 0+5 to the server. The second click, dispatched before the first returned and
        updated the accumulated value, also sent 0+5 rather than the expected 5+5. Thus, both invocations returned 5.
        Oops.
    </p>
    <h2>Another Example</h2>
    <p>
        One of the reasons we are interested in getting AJAX right is that we write life critical applications that
        could potentially have an adverse effect on someone's life. Snafus like our bogus calculator are a big deal
        for us. Let's take a shot at a widget browser like the one at http://www.apple.com/downloads/dashboard/.
        When the user selects a category, our widget browser requests a list of widgets for that category. Either we
        have a fast user or a slow server, but things don't look right because we see the Asteroid Widget when the
        Food category was selected. What happened? I don't know exactly, but here's one scenario. The user has been
        clicking wildly and the network has been a bit erratic. The user clicked Games and then quickly chose Food. The
        first request got hung up a bit with some unfortunate packet resends and returned <em>after</em> the second
        request. Bingo, you see the game widgets while the Food category is selected. No big deal you say? What if
        the selector was Patient instead of Category and the result a wicked cocktail dosage rather than a set of
        widgets? Not so tight.
    </p>
    <h2>Solutions</h2>
    <p>
        The most general solution we have is to always check whether or not an operation is still appropriate when it
        returns and react, well, appropriately if it is not. We do not have general rules for checking appropriateness
        or responding appropriately to all situations. The programmer inside you will have to figure it out. We do
        have a few techniques that work an many situations, to the point where they are realized in BHF as canned
        options, for you to consider as a starting point.
    </p>
        <h3>Stay Away From Server Side State</h3>
        <p>
            This is the RESTful side of our solution. Consider if we had kept the accumulated value of our calculator
            server side instead of client side. Sweet you say, we would have had 10 as expected. Well yes, but we
            would have another problem. Suppose, one of the additions never returned. Should we retry? It turns out
            that you, despite all the tricks you might be thinking, have no choice but to fail because you have no
            way to know for sure whether or not the addition occurred in the server. The operation was not idempotent.
            By using client side state, the operations are idempotent and can be repeated until successful.
        </p><p>
            Sometimes you have to have mutable server side state, such as a database. Suppose you want to change your
            last name to Chamberlain in the personal profile. Changing to something is idempotent: do it twice and you
            have the same end result. What about transferring $100 between two accounts? To make this transfer idempotent
            you can introduce a transaction ID that represents the single transfer. If the operation shows up with
            a transaction ID that has already been used, ignore it. Regardless of how many times you repeat the operation,
            the end result is the same. (Notice the difference between ignoring and throwing an error. Throwing an
            error foils the idempotency, strictly speaking.)
        </p>
        <h3>One at a Time Please</h3>
        <p>
            As with the calculator, the input to one operation often depends on the result of a previous operation, <em>
            even if the subsequent operation was initiated before the prior operation returned</em>. We see this
            constraint frequently with components, which have state, rather than services, which are stateless. Usually
            the user expects an operation on a component to capture the arguments of the operation at the time of user
            interaction, but to capture the component state after all the pending operations have been completed. For
            example, if the user says 'add 5', she means 5 even if she enters another operand while the operation is
            pending; however, the accumulated is not necessarily the value at 'add 5' time, but the value after all
            operations pending at that time have completed.
        </p><p>
            This observation of expected behavior lead us to serialize operations tied to common state: a Component in the
            BHF. Its OK to overlap operations in different components, but you should usually serialize operations within
            a given Component as one operation is likely to depend on the Component state, which might be changed by a
            prior operation. In contrast, BHF Services have no state, so overlapping operations on Service will usually
            work out.
        </p><p>
            As we have assumed, within the scope of a single Component, the result of a given operation depends on the
            results of prior operations, one can also infer that a failure in one operation nullifies the relevance of
            pending operations on the same Component.
        </p><p>
            The critical reader will be take issue with our assumed coupling of all operations within the scope of a
            single Component, with justification. Of course, some operations, such as simple accessors, do not modify
            state and so do not impact subsequent operations. In fact, we originally coded reader/writer access control
            into BHF Components, but found the complexity too much for a minimal observed gain in liveness.
        </p>
        <h3>Check Input State</h3>
        <p>
            An operation accepts certain input state. If that state has not changed when the response is received, its a
            good bet (but not a guaranteed in some cases) that the result is still relavant. This policy would have
            prevented displaying the Game widgets when the Food category was selected because the input was the
            category selected, which changed during the operation.
        </p>
        <h3>Rollback?</h3>
        <p>
            So what might be an appropriate reaction to a fail precondition check (a check for the appropriateness of
            a response)? The three response we use most often are as follows.
        </p>
            <ul>
                <li>Ignore the response. With the widget browser, we can ignore the response because we know there's
                an appropriate response out there, arrived or pending. The only catch is what happens if that
                appropriate response never arrives because of an error?</li>
                <li>If your operation is idempotent, there's no harm (at least to state) in retrying the operation
                with the current state, such as the current widget Category selection.</li>
                <li>If you do not know how to continue in the face of an inappropriate response, rollback the
                application back to a consistent state: perhaps a page refresh and back step in the history. Do let
                the user know what you are up to.</li>
                <li>If you cannot rollback, throw up your arms, take comfort in the fact that it does not happen
                frequently, confess the situation to your user, and consider if a bit of restructuring of your
                application might keep you from this place.</li>
            </ul>
        <h3>Be Optimistic</h3>
        <p>
            With all this gloom-and-doom, you would think AJAX would not work at all, but, in fact, most applications
            work fine as long as the user is not more active than the server is responsive. The paucity of errors tells
            us that we would be better off detecting and recovering from the occasional problem than trying to prevent
            all possible problems by design. For example, we can block the user from making any changes are interacting
            with any Component while an operation is pending, and thus prevent state changes out from under the operation,
            or we can allow the user to motor on and check, when the operation returns, whether something relevant to
            the operation has been changed. The later make require some recovery work or notifying the user that something
            has gone awry (this is what gmail now does), but it happens infrequently. At this point in time, the trend
            is toward letting the user continue to interact with at least parts of the application, which we can accomodate
            with our check and recover approach.
        </p>
    <h2>Conclusion</h2>
    <p>
        This paper contains an inordinate number of usually's. As we gain experience with AJAX and pause from time-to-time
        to consider the inherent difficulties and possible solutions, perhaps we will have more definite guidelines,
        perhaps even rules, for doing AJAX safely. Until then, never blindly apply the result of an AJAX operation,
        always check if the operation, as dispatched, is still appropriate and react appropriately if it is not.
    </p>
</body>
</html>